<!--
 * @Author: WuFeng <763467339@qq.com>
 * @Date: 2024-11-11 09:54:10
 * @LastEditTime: 2024-11-12 17:57:52
 * @LastEditors: WuFeng <763467339@qq.com>
 * @Description: pdf 预览
 * @FilePath: \markdown-magic\src\pages\Pdf\components\PdfPreview.vue
 * Copyright 版权声明
-->
<template>
  <div class="pdf-wrapper">
    <a-spin :tip="spinningConfig.tip" :spinning="spinningConfig.spinning">
      <div ref="pdfContainer" class="pdf-container" @mousedown="onMouseDown">
        <!-- PDF的canvas将会插入到这里 -->
      </div>
      <div class="controls">
        <a-button @click="prevPage"><LeftOutlined />上一页</a-button>
        <a-button @click="nextPage">下一页<RightOutlined /></a-button>
        <a-button @click="zoomIn"><PlusCircleOutlined />放大</a-button>
        <a-button @click="zoomOut"><MinusCircleOutlined />缩小</a-button>
        <!-- <a-button @click="downloadPDF" type="primary" ghost><DownloadOutlined/>下载</a-button> -->
        <div class="page-wrapper">
          当前第{{ currentPage }}页，共{{ totalPages }}页
        </div>
      </div>
    </a-spin>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted } from "vue"
import * as pdfjsLib from "pdfjs-dist"
import * as workerSrc from "pdfjs-dist/build/pdf.worker.min?url"
import { PDFDocument } from "pdf-lib"
import {
  LeftOutlined,
  RightOutlined,
  PlusCircleOutlined,
  MinusCircleOutlined,
  DownloadOutlined
} from '@ant-design/icons-vue'

// demo的pdf的路径是从父组件传入在onMounted中进行赋值
const props = defineProps(["src"])

// loading 配置
const spinningConfig = reactive({
  spinning: true,
  tip: '处理中...'
})

// 配置 PDF.js worker 的路径
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc.default;

const pdfContainer = ref(null); // pdf容器
const pdfUrl = ref(""); // 可替换为你的 PDF 文件路径
let pdfDoc = null; // pdf显示内容
let scale = ref(1.0); // 缩放比例
let currentPage = ref(1); // 当前页
let totalPages = ref(0); // 总页数
let isDragging = ref(false); // 是否可拖拽
let startX = ref(0); // 拖拽的x轴
let startY = ref(0); // 拖拽的y轴
let scrollLeft = ref(0); // 滚动的left
let scrollTop = ref(0); // 滚动的top

onMounted(async () => {
  //对pdf的url进行赋值
  pdfUrl.value = props.src;
  //使用pdfjs-dist对pdf进行解析，该步骤为异步
  const loadingTask = pdfjsLib.getDocument({data: pdfUrl.value})
  pdfDoc = await loadingTask.promise;
  // console.log(`🚀 ~ onMounted ~ pdfDoc:`, pdfDoc)
  //获取到总页数
  totalPages.value = pdfDoc.numPages
  //使用渲染方法
  renderPage(currentPage.value)
});

//渲染方法（）
const renderPage = async (num) => {
  spinningConfig.spinning = true
  
  const page = await pdfDoc.getPage(num);
  const viewport = page.getViewport({ scale: scale.value })
  const canvas = document.createElement("canvas")
  const context = canvas.getContext("2d")
  canvas.height = viewport.height
  canvas.width = viewport.width

  const renderContext = {
    canvasContext: context,
    viewport: viewport
  }
  await page.render(renderContext).promise
  pdfContainer.value.innerHTML = ""
  pdfContainer.value.appendChild(canvas)
  
  spinningConfig.spinning = false
};

//放大
const zoomIn = () => {
  scale.value += 0.1;
  renderPage(currentPage.value)
};

//缩小
const zoomOut = () => {
  if (scale.value > 0.2) {
    scale.value -= 0.1;
    renderPage(currentPage.value)
  }
};

//下一页
const nextPage = () => {
  if (currentPage.value < totalPages.value) {
    currentPage.value += 1
    renderPage(currentPage.value)
  }
};

//上一页
const prevPage = () => {
  if (currentPage.value > 1) {
    currentPage.value -= 1
    renderPage(currentPage.value)
  }
}

//下载
const downloadPDF = async () => {
  const existingPdfBytes = await fetch(pdfUrl.value).then((res) =>
    res.arrayBuffer()
  )
  const pdfDoc = await PDFDocument.load(existingPdfBytes)
  const pdfBytes = await pdfDoc.save()
  const blob = new Blob([pdfBytes], { type: "application/pdf" })
  const link = document.createElement("a")
  link.href = window.URL.createObjectURL(blob);
  link.download = "downloaded.pdf"
  link.click()
}

//用于实现拖拽
//鼠标按下
const onMouseDown = (e) => {
  isDragging.value = true
  startX.value = e.pageX - pdfContainer.value.offsetLeft
  startY.value = e.pageY - pdfContainer.value.offsetTop
  scrollLeft.value = pdfContainer.value.scrollLeft
  scrollTop.value = pdfContainer.value.scrollTop
  document.addEventListener("mousemove", onMouseMove)
  document.addEventListener("mouseup", onMouseUp)
}

//鼠标移动
const onMouseMove = (e) => {
  if (!isDragging.value) return
  const x = e.pageX - pdfContainer.value.offsetLeft
  const y = e.pageY - pdfContainer.value.offsetTop
  const walkX = x - startX.value
  const walkY = y - startY.value
  pdfContainer.value.scrollLeft = scrollLeft.value - walkX
  pdfContainer.value.scrollTop = scrollTop.value - walkY
}

//鼠标抬起
const onMouseUp = () => {
  isDragging.value = false
  document.removeEventListener("mousemove", onMouseMove)
  document.removeEventListener("mouseup", onMouseUp)
}

</script>

<style lang="scss" scoped>
.pdf-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  border: 1px solid #ccc;
  padding: 52px 8px 8px;
}

.pdf-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow: auto;
  cursor: grab;
}

.pdf-container:active {
  cursor: grabbing;
}

.controls {
  position: absolute;
  top: 10px;
  right: 10px;
  left: 10px;
  display: flex;
  justify-content: center;
  gap: 10px;
}

button {
  padding: 5px 10px;
  cursor: pointer;
}

.page-wrapper {
  font-size: 16px;
  color: #fff;
  background-color: #f00;
  padding: 3px 10px;
  margin-top: 8px;
  // position: fixed;
  // bottom: 10px;
}

</style>